/**
 * Copyright (c) 2010 sonntagsfarben.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
 
package de.sonntagsfarben.effects 
{
	import com.greensock.TweenLite;

	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.geom.Rectangle;

	/**
	 * Mask transition effect for ActionsScript 3.0
	 * 
	 * <p>Maskeffect to fade in or out your content</p>
	 * 
	 * @playerversion Flash 9
	 * @langversion 3.0
	 *
	 * @package    de.sonntagsfarben.effects
	 * @author     Soenke Kluth <sonntagsfarben.de>
	 * @copyright  2009 sonntagsfarben.de
	 * @version    0.6
	 */

	public class Mask 
	{

		public static const ROUNDRECT : String = "roundrect";
		public static const RECTANGLE : String = "rectangle";
		public static const ELLIPSE : String = "ellipse";

		public static const LEFT : String = "left";
		public static const RIGHT : String = "right";
		public static const TOP : String = "top";
		public static const BOTTOM : String = "bottom";
		public static const CENTER : String = "center";

		//TODO implement::
		public static const TOP_LEFT : String = "topleft";
		public static const TOP_RIGHT : String = "topright";
		public static const BOTTOM_LEFT : String = "bottomleft";
		public static const BOTTOM_RIGHT : String = "bottomright";

		//TODO implement individual point
		public static const POINT : String = "point";

		private static const DESTINATION_IN : String = "in";
		private static const DESTINATION_OUT : String = "out";

		private var _destination : String;
		private var _target : DisplayObject;
		private var _duration : Number;
		private var _vars : MaskVars;
		private var _mask : DisplayObject;
		private var _hasStageListener : Boolean;
		private var _isTweening : Boolean;
		
		public var debug:Boolean = false;

		public function Mask(target : DisplayObject, duration : Number, vars : Object) 
		{
			_target = target;
			_duration = duration;
			_vars = _initVars(vars);
			onInit(null);
		}

		private function onInit(event : Event) : void 
		{
			if(_target.stage == null) {
				_hasStageListener = true;
				_target.addEventListener(Event.ADDED_TO_STAGE, onInit, false, 0, true);
				return;
			}
			_init();
			_createMask();
			_tweenMask();
		}

		private function _initVars(vars : Object) : MaskVars
		{
			if(vars is MaskVars)
				return vars as MaskVars;
			
			var tmpVars : MaskVars = new MaskVars();
				
			for (var i : String in vars) {
				try {
					tmpVars[i] = vars[i];
				}catch(any : *) {
					trace(this + " Warning : " + i + " : value is invalid");
					return null;
				}				
			}
			return tmpVars;
		}

		private function _init() : void 
		{
			if(_vars["_destination"] == undefined)
				_vars["_destination"] = DESTINATION_IN;
			_destination = _vars["_destination"];
		}

		
		public static function fadeIn(target : DisplayObject, duration : Number, vars : Object) : Mask
		{
			vars["_destination"] = DESTINATION_IN;
			return new Mask(target, duration, vars);
		}

		public static function fadeOut(target : DisplayObject, duration : Number, vars : Object) : Mask
		{
			vars["_destination"] = DESTINATION_OUT;
			return new Mask(target, duration, vars);
		}

		
		private function _createMask() : void
		{
			var rect : Rectangle = _target.getBounds(_target.parent);
			
			_mask = new MaskShape(0, 0, rect.width, rect.height, _vars.shape);
			
			switch(_vars.direction) {
				
				case LEFT:
				case TOP_LEFT:
					_mask.scaleX = _destination == DESTINATION_IN ? 0 : 1;
					_mask.x = rect.x;
					_mask.y = rect.y;
					(_vars.direction == TOP_LEFT) ? (_mask.scaleY = _destination == DESTINATION_IN ? 0 : 1) : null;
					break;	
									
				case RIGHT:
				case TOP_RIGHT:
					_mask.x = rect.x + rect.width;
					_mask.y = rect.y ;
					_mask.scaleX = _destination == DESTINATION_IN ? 0 : -1;
					(_vars.direction == TOP_RIGHT) ? (_mask.scaleY = _destination == DESTINATION_IN ? 0 : 1) : null;
					break;
				
				case TOP:
					_mask.scaleY = _destination == DESTINATION_IN ? 0 : 1;
					_mask.x = rect.x;
					_mask.y = rect.y;
					break;	
				
				case BOTTOM:
					_mask.y = rect.y + rect.height;
					_mask.x = rect.x;
					_mask.scaleY = _destination == DESTINATION_IN ? 0 : -1;
					break;	
					
				case CENTER:
					_mask = new MaskShape(-rect.width * .5, -rect.height * .5, rect.width, rect.height, _vars.shape);
					_mask.y = rect.y + rect.height * 0.5;
					_mask.x = rect.x + rect.width * 0.5;
					_mask.scaleX = _mask.scaleY = _destination == DESTINATION_IN ? 0 : 1;
					break;	
					
				case TOP_LEFT:
					break;
				case TOP_RIGHT:
					break;
				case BOTTOM_LEFT:
					break;
				case BOTTOM_RIGHT:
					break;
				case POINT:
					break;	
			}
			
			//TODO mask komplett löschen??!!!
			if(_target.mask is MaskShape) {
				_target.parent.removeChild(_target.mask);
				_target.mask = null;
			}
			
			if(!debug)
				_target.mask = _mask;
			_target.parent.addChild(_mask);
		}

		
		
		private function _tweenMask() : void
		{
			var tweenVars : Object = new Object();
			tweenVars.onComplete = onComplete;
			tweenVars.delay = _vars.delay;
			tweenVars.ease = _vars.ease;
			
			switch(_vars.direction) {
				case LEFT:
				case TOP_LEFT:
					tweenVars.scaleX = _destination == DESTINATION_IN ? 1 : 0;
					(_vars.direction == TOP_LEFT) ? (tweenVars.scaleY = _destination == DESTINATION_IN ? 1 : 0) : null;
					break;
				case RIGHT:
				case TOP_RIGHT:
					tweenVars.scaleX = _destination == DESTINATION_IN ? -1 : 0;
					(_vars.direction == TOP_RIGHT) ? (tweenVars.scaleY = _destination == DESTINATION_IN ? 1 : 0) : null;
					break;
				case TOP:
					tweenVars.scaleY = _destination == DESTINATION_IN ? 1 : 0;
					break;
				case BOTTOM:
					tweenVars.scaleY = _destination == DESTINATION_IN ? -1 : 0;
					break;
				case CENTER:
					tweenVars.scaleX = tweenVars.scaleY = _destination == DESTINATION_IN ? 1 : 0;
					break;
			}
			
			if(_vars.onStart != null) {
//				_vars.onStart.call();
			}
			_isTweening = true;
			TweenLite.to(_mask, _duration, tweenVars);	
		}

		
		private function onComplete() : void 
		{
			_isTweening = false;
			var callback : Function;
			if(_vars.onComplete != null) {
				callback = (_vars.onComplete as Function);
			}
			destroy(_destination == DESTINATION_IN);
			if(callback != null)
				callback.call();
		}

		
		public function destroy(removeMask : Boolean = true) : void
		{
			if(removeMask) {
				if(_target.parent)
					if(_target.parent.contains(_mask))
						_target.parent.removeChild(_mask);
				if(_target.mask == _mask)		
					_target.mask = null;
			}
			if(_hasStageListener) {
				_target.removeEventListener(Event.ADDED_TO_STAGE, onInit);
			}
			_isTweening = false;
			_mask = null;
			_target = null;
			_vars = null;
		}
		
		
		public function get isTweening() : Boolean
		{
			return _isTweening;
		}
	}
}

import de.sonntagsfarben.effects.Mask;

import flash.display.Shape;

internal class MaskShape extends Shape
{
	public function MaskShape(x : Number, y : Number, width : Number, height : Number, shape : String = Mask.RECTANGLE) 
	{
		
		graphics.beginFill(0xff0000);

		switch (shape) {
			case Mask.RECTANGLE:
			default:
				graphics.drawRect(x, y, width, height);
				break;
			case Mask.ROUNDRECT:
				//if (direction == BOTTOM_IN || direction == BOTTOM_OUT)
				//mask.graphics.drawRoundRect(x - 5, y + 5, width + 10, height - 10, 20, 20);
				//else
				graphics.drawRoundRect(x - 5, y - 5, width + 10, height + 10, 30, 30);
			break;
			case Mask.ELLIPSE:
				var radius : Number = width >= height ? width : height;
				graphics.drawEllipse(x, y, radius, radius);
				break;
		}

		graphics.endFill();
	}
}



